package com.music.message.service.impl;

import com.music.common.core.constant.Constants;
import com.music.common.core.constant.SecurityConstants;
import com.music.common.core.domain.R;
import com.music.common.core.enums.ExceptionCode;
import com.music.common.core.exception.CustomException;
import com.music.common.redis.service.RedisService;
import com.music.message.service.UserMessageService;
import com.music.message.utils.MessageUtils;
import com.music.user.api.RemoteUserService;
import com.music.user.domain.User;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Author 史豪通
 * Date 2024/10/11 19:39
 */
@Service
public class UserMessageServiceImpl implements UserMessageService {
    @Resource
    MessageUtils messageUtils;
    @Resource
    RedisService redisService;
    @Resource
    RabbitTemplate rabbitTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    RemoteUserService remoteUserService;

    @Override
    @RabbitListener(queues = {Constants.MESSAGE_USER_QUEUE})
    public void ampqListenerUser(String phone) {
        messageUtils.sendUser(phone);
    }

    @Override
    public void ampqSend(String phone, String exchange, String routing, String limitKeyPreFix) {
        // 使用布隆过滤器，判断用户是否存在于数据库中
        Long result = findUserAccount(phone);

        if (result.intValue() == 1) {
            // 查询数据库 验证布隆过滤器是否误判
            R<User> userResult = remoteUserService.findUserByAccount(phone, SecurityConstants.INNER);
            User login = userResult.getData();
            if (login != null)
                throw new CustomException(ExceptionCode.USER_ALREADY_REGISTERED);
        }

        String limitKey = limitKeyPreFix + phone;
        // 防止恶意刷验证码
        Long cnt = redisService.redisTemplate.opsForValue().increment(limitKey);
        if (cnt == 1) {
            redisService.expire(limitKey, 5, TimeUnit.MINUTES);
        }
        if (cnt > 3) {
            throw new CustomException(ExceptionCode.CELL_PHONE_VERIFY_CODE_LIMIT);
        }

        rabbitTemplate.convertAndSend(exchange,
                routing,
                phone
        );
    }

    @Override
    public void ampqSendUserRegister(String phone) {
        ampqSend(phone, Constants.MESSAGE_USER_EXCHANGE, Constants.MESSAGE_USER_ROUTING, Constants.MESSAGE_USER_CNT_REGISTER);
    }

    @Override
    public void ampqCheck(String phone, String code) {
        messageUtils.checkUser(phone, code);
    }

    public Long findUserAccount(String userAccount) {
        String script = "return tonumber(redis.call(\"bf.exists\", KEYS[1], ARGV[1]))";

        return stringRedisTemplate.opsForValue()
                .getOperations()
                .execute(new DefaultRedisScript<>(script, Long.class),
                        new ArrayList<String>() {{
                            add(Constants.WHITE_USER_ACCOUNT_KEY);
                        }},
                        userAccount);
    }
}
